#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
HygonJDK 调优助手 - 自动化分析脚本
简化使用步骤，自动获取Java进程PID并执行相应分析

使用方法:
  python3 autotune_analyzer.py [选项]

选项:
  --jstack     自动分析线程堆栈和锁竞争
  --gc         分析GC日志 (需要指定GC日志文件路径)
  --context    分析上下文切换 (需要指定perf日志文件路径)
  --all        执行所有可用的分析
  --pid PID    指定要分析的Java进程PID (默认自动查找)
  --gc-file    指定GC日志文件路径
  --perf-file  指定perf日志文件路径
  --help       显示帮助信息

示例:
  python3 autotune_analyzer.py --jstack
  python3 autotune_analyzer.py --all
  python3 autotune_analyzer.py --gc --gc-file /path/to/gc.log
  python3 autotune_analyzer.py --context --perf-file /path/to/summary.txt
"""

import os
import sys
import subprocess
import argparse
import tempfile
import shutil
from pathlib import Path

def find_java_pids():
    """自动查找Java进程PID"""
    try:
        result = subprocess.run(['pgrep', 'java'], capture_output=True, text=True)
        if result.returncode == 0 and result.stdout.strip():
            pids = [pid.strip() for pid in result.stdout.strip().split('\n') if pid.strip()]
            return pids
        else:
            print("❌ 未找到运行的Java进程")
            return []
    except Exception as e:
        print(f"❌ 查找Java进程时出错: {e}")
        return []

def select_pid(pids):
    """让用户选择要分析的PID"""
    if not pids:
        return None
    
    if len(pids) == 1:
        print(f"✅ 找到Java进程: PID={pids[0]}")
        return pids[0]
    
    print("📋 找到多个Java进程:")
    for i, pid in enumerate(pids, 1):
        try:
            # 尝试获取进程命令行信息
            cmd_result = subprocess.run(['ps', '-p', pid, '-o', 'command', '--no-headers'], 
                                      capture_output=True, text=True)
            cmd_info = cmd_result.stdout.strip()[:80] + "..." if len(cmd_result.stdout.strip()) > 80 else cmd_result.stdout.strip()
            print(f"  {i}. PID={pid} - {cmd_info}")
        except:
            print(f"  {i}. PID={pid}")
    
    try:
        choice = input("请选择要分析的进程编号 (默认选择1): ").strip()
        if not choice:
            choice = '1'
        selected_pid = pids[int(choice) - 1]
        print(f"✅ 选择进程: PID={selected_pid}")
        return selected_pid
    except (ValueError, IndexError):
        print("❌ 无效选择，使用第一个进程")
        return pids[0]

def analyze_jstack(pid=None):
    """自动执行jstack分析"""
    if not pid:
        pids = find_java_pids()
        pid = select_pid(pids)
        if not pid:
            return False
    
    print(f"🔍 正在分析线程堆栈 (PID={pid})...")
    
    try:
        # 执行jstack命令
        jstack_result = subprocess.run(['jstack', '-l', str(pid)], capture_output=True, text=True)
        
        if jstack_result.returncode != 0:
            print(f"❌ jstack命令执行失败: {jstack_result.stderr}")
            return False
        
        # 将输出传递给analyze_jstack.py
        analyze_result = subprocess.run([sys.executable, 'analyze_jstack.py'], 
                                      input=jstack_result.stdout, 
                                      text=True, 
                                      capture_output=False)
        
        if analyze_result.returncode == 0:
            print("✅ jstack分析完成")
            return True
        else:
            print("❌ jstack分析失败")
            return False
            
    except Exception as e:
        print(f"❌ jstack分析过程中出错: {e}")
        return False

def analyze_gc(gc_file=None, generate_sample=False):
    """分析GC日志"""
    if not gc_file:
        # 尝试查找常见的GC日志文件
        common_paths = [
            './gc.log',
            '/tmp/gc.log',
            '/var/log/gc.log',
            './sample_gc.log'
        ]
        
        for path in common_paths:
            if os.path.exists(path):
                gc_file = path
                break
        
        if not gc_file:
            if generate_sample:
                print("📝 未找到GC日志文件，正在生成示例GC日志...")
                try:
                    generate_result = subprocess.run([sys.executable, 'generate_gc_log.py', '--sample'],
                                                   capture_output=True, text=True)
                    if generate_result.returncode == 0:
                        gc_file = 'sample_gc.log'
                        print("✅ 示例GC日志生成完成")
                    else:
                        print("❌ 示例GC日志生成失败")
                        return False
                except Exception as e:
                    print(f"❌ 生成示例GC日志时出错: {e}")
                    return False
            else:
                print("❌ 未找到GC日志文件，请使用 --gc-file 参数指定文件路径")
                print("💡 提示: 可以使用 --generate-gc 参数生成示例GC日志")
                return False
    
    if not os.path.exists(gc_file):
        print(f"❌ GC日志文件不存在: {gc_file}")
        return False
    
    print(f"🔍 正在分析GC日志: {gc_file}")
    
    try:
        with open(gc_file, 'r', encoding='utf-8', errors='ignore') as f:
            gc_content = f.read()
        
        # 将内容传递给analyze_gc.py
        analyze_result = subprocess.run([sys.executable, 'analyze_gc.py'], 
                                      input=gc_content, 
                                      text=True, 
                                      capture_output=False)
        
        if analyze_result.returncode == 0:
            print("✅ GC分析完成")
            return True
        else:
            print("❌ GC分析失败")
            return False
            
    except Exception as e:
        print(f"❌ GC分析过程中出错: {e}")
        return False

def analyze_context_switch(perf_file=None):
    """分析上下文切换"""
    if not perf_file:
        # 尝试查找常见的perf日志文件
        common_paths = [
            './summary.txt',
            './perf.data.txt',
            '/tmp/summary.txt'
        ]
        
        for path in common_paths:
            if os.path.exists(path):
                perf_file = path
                break
        
        if not perf_file:
            print("❌ 未找到perf日志文件，请使用 --perf-file 参数指定文件路径")
            return False
    
    if not os.path.exists(perf_file):
        print(f"❌ perf日志文件不存在: {perf_file}")
        return False
    
    print(f"🔍 正在分析上下文切换: {perf_file}")
    
    try:
        with open(perf_file, 'r', encoding='utf-8', errors='ignore') as f:
            perf_content = f.read()
        
        # 将内容传递给analyze_context_switch.py
        analyze_result = subprocess.run([sys.executable, 'analyze_context_switch.py'], 
                                      input=perf_content, 
                                      text=True, 
                                      capture_output=False)
        
        if analyze_result.returncode == 0:
            print("✅ 上下文切换分析完成")
            return True
        else:
            print("❌ 上下文切换分析失败")
            return False
            
    except Exception as e:
        print(f"❌ 上下文切换分析过程中出错: {e}")
        return False

def collect_perf_data(duration=30):
    """自动采集perf数据"""
    print(f"📊 正在采集 {duration} 秒的上下文切换数据...")
    
    try:
        # 检查perf命令是否可用
        check_result = subprocess.run(['which', 'perf'], capture_output=True)
        if check_result.returncode != 0:
            print("❌ perf命令不可用，请安装linux-tools包")
            return False
        
        print(f"⚠️  注意: 由于权限限制，需要手动执行以下命令:")
        print(f"    sudo perf record -e sched:sched_switch -a sleep {duration}")
        print(f"    sudo perf script -i perf.data > summary.txt")
        print(f"💡 提示: 执行完成后，可以使用 --context 参数分析生成的 summary.txt 文件")
        
        # 尝试自动执行，但可能因为sudo权限问题失败
        try:
            # 执行perf记录
            perf_record_cmd = ['sudo', 'perf', 'record', '-e', 'sched:sched_switch', '-a', 'sleep', str(duration)]
            print(f"尝试执行命令: {' '.join(perf_record_cmd)}")
            
            record_result = subprocess.run(perf_record_cmd, capture_output=True, text=False, timeout=duration+10)
            if record_result.returncode != 0:
                print(f"❌ perf记录失败: {record_result.stderr.decode('utf-8', errors='ignore')}")
                return False
            
            # 等待一下确保文件创建
            import time
            time.sleep(1)
            
            # 检查perf.data文件是否创建
            if not os.path.exists('perf.data'):
                print("❌ perf.data文件未创建，请检查perf命令权限")
                return False
            
            # 导出perf数据
            print("📝 正在导出perf数据...")
            with open('summary.txt', 'w', encoding='utf-8') as f:
                script_result = subprocess.run(['sudo', 'perf', 'script', '-i', 'perf.data'],
                                             stdout=f, text=False, stderr=subprocess.PIPE)
            
            if script_result.returncode == 0:
                print("✅ perf数据采集完成，文件: summary.txt")
                return True
            else:
                print(f"❌ perf数据导出失败: {script_result.stderr.decode('utf-8', errors='ignore')}")
                return False
                
        except subprocess.TimeoutExpired:
            print("❌ perf记录超时，请手动执行命令")
            return False
        except Exception as e:
            print(f"❌ perf数据采集过程中出错: {e}")
            print("💡 请手动执行上述命令")
            return False
            
    except Exception as e:
        print(f"❌ perf数据采集过程中出错: {e}")
        return False

def main():
    parser = argparse.ArgumentParser(description='HygonJDK 调优助手 - 自动化分析脚本')
    parser.add_argument('--jstack', action='store_true', help='自动分析线程堆栈和锁竞争')
    parser.add_argument('--gc', action='store_true', help='分析GC日志')
    parser.add_argument('--generate-gc', action='store_true', help='生成示例GC日志并分析')
    parser.add_argument('--context', action='store_true', help='分析上下文切换')
    parser.add_argument('--collect-perf', type=int, metavar='SECONDS',
                       help='采集上下文切换数据 (秒数)')
    parser.add_argument('--all', action='store_true', help='执行所有可用的分析')
    parser.add_argument('--pid', type=int, help='指定要分析的Java进程PID')
    parser.add_argument('--gc-file', help='指定GC日志文件路径')
    parser.add_argument('--perf-file', help='指定perf日志文件路径')
    
    args = parser.parse_args()
    
    # 如果没有指定任何操作，显示帮助
    if not any([args.jstack, args.gc, args.generate_gc, args.context, args.all, args.collect_perf]):
        parser.print_help()
        return
    
    print("======================================================================")
    print("HygonJDK 调优助手 - 自动化分析")
    print("======================================================================")
    
    success_count = 0
    total_count = 0
    
    # 采集perf数据
    if args.collect_perf:
        total_count += 1
        if collect_perf_data(args.collect_perf):
            success_count += 1
            # 如果采集成功且用户要求分析上下文切换，则自动分析
            if args.context or args.all:
                total_count += 1
                if analyze_context_switch('summary.txt'):
                    success_count += 1
    
    # 分析线程堆栈
    if args.jstack or args.all:
        total_count += 1
        if analyze_jstack(args.pid):
            success_count += 1
    
    # 分析GC日志
    if args.gc or args.all:
        total_count += 1
        if analyze_gc(args.gc_file):
            success_count += 1
    
    # 生成并分析GC日志
    if args.generate_gc:
        total_count += 1
        if analyze_gc(generate_sample=True):
            success_count += 1
    
    # 分析上下文切换 (如果不包含在collect-perf中)
    if args.context and not args.collect_perf:
        total_count += 1
        if analyze_context_switch(args.perf_file):
            success_count += 1
    
    print("======================================================================")
    print(f"分析完成: {success_count}/{total_count} 项分析成功")
    print("======================================================================")

if __name__ == '__main__':
    main()